package de.sky.mathparser.parser.syntaxtree;

import java.util.ArrayList;
import java.util.List;

public class AbstractSyntaxTree implements Evaluatable {

	private AbstractSyntaxTree parent = null;
	private List<AbstractSyntaxTree> children = new ArrayList<>();

	private double value = 0.0;
	private char operator = 0;

	private AbstractSyntaxTree(AbstractSyntaxTree parent) {
		this.parent = parent;
	}

	public AbstractSyntaxTree() {
		this(null);
	}

	public AbstractSyntaxTree(double number) {
		this.value = number;
	}

	public AbstractSyntaxTree openBranch() {
		AbstractSyntaxTree tmp = null;

		if (this.parent == null) {
			tmp = this;
		} else {
			tmp = new AbstractSyntaxTree(this);
			children.add(tmp);
		}

		return tmp;
	}

	public AbstractSyntaxTree closeBranch() {
		if (parent != null)
			return this.parent;
		return this;
	}

	public void add(char operator) {
		this.operator = operator;
	}

	public void add(int i, double number) {
		this.children.add(i, new AbstractSyntaxTree(number));
	}

	@Override
	public String toString() {
		if (operator == 0)
			return "" + this.value;
		return this.operator + " " + this.children.toString();
	}

	@Override
	public double evaluate() {
		switch (operator) {
		case 0:
			return value;
		case '+': {
			double val = 0.0;
			for (AbstractSyntaxTree tmp : children)
				val += tmp.evaluate();
			return val;
		}
		case '-': {
			double val = 0.0;
			for (AbstractSyntaxTree tmp : children)
				val -= tmp.evaluate();
			return val;
		}
		case '*': {
			double val = 0.0;
			for (AbstractSyntaxTree tmp : children)
				val *= tmp.evaluate();
			return val;
		}
		case '/': {
			double val = 0.0;
			for (AbstractSyntaxTree tmp : children)
				val /= tmp.evaluate();
			return val;
		}
		case '%': {
			double val = 0.0;
			for (AbstractSyntaxTree tmp : children)
				val %= tmp.evaluate();
			return val;
		}
		default:
			assert (false);
			return 0.0;
		}

	}
}
